#include "ftpserverpi.h"

FtpServerPI::FtpServerPI(qintptr socketDescriptor, const ServerConfig &serverConfig, QObject *parent) :
    QObject(parent),
    m_socketDescriptor(socketDescriptor),
    m_serverConfig(serverConfig)
{

}

FtpServerPI::~FtpServerPI()
{

}

void FtpServerPI::init()
{
    m_socket = new QTcpSocket;

    connect(m_socket, SIGNAL(readyRead()), this, SLOT(onReadyRead()));
    connect(m_socket, SIGNAL(error(QAbstractSocket::SocketError)),
            this, SLOT(onError(QAbstractSocket::SocketError)));
    connect(m_socket, SIGNAL(disconnected()), this, SLOT(onDisconnected()));

    m_socket->setSocketDescriptor(m_socketDescriptor);
    m_socket->write("220 Welcome to Simple FTP Server\r\n");
}

void FtpServerPI::clean()
{
    delete m_socket;
}

void FtpServerPI::onReadyRead()
{
    while (m_socket->canReadLine())
        m_commandQueue.append(FtpCommand(m_socket->readLine()));

    startNextCommand();
}

void FtpServerPI::onError(QAbstractSocket::SocketError error)
{
    qDebug() << "error";
}

void FtpServerPI::onDisconnected()
{
    qDebug() << "disconnected";
}

void FtpServerPI::startNextCommand()
{
    if (!m_currentCommand.isNull() || m_commandQueue.isEmpty())
        return;

    m_currentCommand = m_commandQueue.takeFirst();
    QByteArray cmd = m_currentCommand.cmd();
    if (cmd == "USER")
        handleUSER();
    else if (cmd == "PASS")
        handlePASS();
    else if (cmd == "PORT")
        handlePORT();
    else if (cmd == "PASV")
        handlePASV();
    else if (cmd == "TYPE")
        handleTYPE();
    else if (cmd == "STRU")
        handleSTRU();
    else if (cmd == "MODE")
        handleMODE();
    else if (cmd == "CWD" || cmd == "XCWD")
        handleCWD();
    else if (cmd == "CDUP")
        handleCDUP();
    else if (cmd == "QUIT")
        handleQUIT();
    else if (cmd == "DELE")
        handleDELE();
    else if (cmd == "RMD" || cmd == "XRMD")
        handleRMD();
    else if (cmd == "MKD" || cmd == "XMKD")
        handleMKD();
    else if (cmd == "PWD" || cmd == "XPWD")
        handlePWD();
    else if (cmd == "RNFR")
        handleRNFR();
    else if (cmd == "RNTO")
        handleRNTO();
    else if (cmd == "LIST")
        handleLIST();
    else if (cmd == "NLST")
        handleNLST();
    else if (cmd == "RETR")
        handleRETR();
    else if (cmd == "STOR")
        handleSTOR();
    else if (cmd == "STOU")
        handleSTOU();
    else if (cmd == "APPE")
        handleAPPE();
    else if (cmd == "ALLO")
        handleALLO();
    else if (cmd == "REST")
        handleREST();
    else if (cmd == "ABOR")
        handleABOR();
    else if (cmd == "SYST")
        handleSYST();
    else if (cmd == "STAT")
        handleSTAT();
    else if (cmd == "HELP")
        handleHELP();
    else if (cmd == "NOOP")
        m_socket->write("200 Command okay.\r\n");
    else
        m_socket->write("502 Command not implemented.\r\n");

    m_lastCommand = m_currentCommand;
    m_currentCommand.setNull();

    if (!m_commandQueue.isEmpty())
        QMetaObject::invokeMethod(this, "startNextCommand", Qt::QueuedConnection);
}

void FtpServerPI::handleUSER()
{
    QByteArray arg = m_currentCommand.arg().toLower();
    if (arg == "ftp" || arg == "anonymous") {
        m_isAnonymous = true;
        m_socket->write("331 Anonymous user okay, need password <e-mail>.\r\n");
    } else {
        m_isAnonymous = false;
        m_socket->write("331 User name okay, need password.\r\n");
    }
}

void FtpServerPI::handlePASS()
{
    if (m_lastCommand.cmd() != "USER") {
        m_socket->write("503 Login with USER first.\r\n");
    } else {
        if (m_isAnonymous
                || m_serverConfig.verifyUser(m_lastCommand.arg(), m_currentCommand.arg())) {
            m_socket->write("230 User logged in.\r\n");
        } else {
            m_socket->write("530 Not logged in.\r\n");
        }
    }
}

void FtpServerPI::handlePORT()
{

}

void FtpServerPI::handlePASV()
{

}

void FtpServerPI::handleTYPE()
{

}

void FtpServerPI::handleSTRU()
{

}

void FtpServerPI::handleMODE()
{

}

void FtpServerPI::handleCWD()
{

}

void FtpServerPI::handleCDUP()
{

}

void FtpServerPI::handleQUIT()
{

}

void FtpServerPI::handleDELE()
{

}

void FtpServerPI::handleRMD()
{

}

void FtpServerPI::handleMKD()
{

}

void FtpServerPI::handlePWD()
{

}

void FtpServerPI::handleRNFR()
{

}

void FtpServerPI::handleRNTO()
{

}

void FtpServerPI::handleLIST()
{

}

void FtpServerPI::handleNLST()
{

}

void FtpServerPI::handleRETR()
{

}

void FtpServerPI::handleSTOR()
{

}

void FtpServerPI::handleSTOU()
{

}

void FtpServerPI::handleAPPE()
{

}

void FtpServerPI::handleALLO()
{

}

void FtpServerPI::handleREST()
{

}

void FtpServerPI::handleABOR()
{

}

void FtpServerPI::handleSYST()
{

}

void FtpServerPI::handleSTAT()
{

}

void FtpServerPI::handleHELP()
{

}


FtpCommand::FtpCommand(const QByteArray &byteArray)
{
    QByteArray str = byteArray.trimmed();
    QList<QByteArray> parts = str.split(' ');
    if (parts.size() > 0) {
        m_cmd = parts.takeFirst().toUpper();
        if (parts.size() > 0)
            m_arg = parts.join(' ').trimmed();
    }
}

QByteArray FtpCommand::cmd() const
{
    return m_cmd;
}

QByteArray FtpCommand::arg() const
{
    return m_arg;
}

bool FtpCommand::isNull() const
{
    return m_cmd.isEmpty();
}

void FtpCommand::setNull()
{
    m_cmd.clear();
    m_arg.clear();
}
